package org.andu.java_gobang.game;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.andu.java_gobang.JavaGobangApplication;
import org.andu.java_gobang.mapper.UserMapper;
import org.andu.java_gobang.pojo.User;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

//这个类表示 一个游戏房间
public class Room {
    //使用Stirng 类型, 方便生成UUID
    private String roomId;

    private User user1;
    private User user2;

    //先手玩家,落白子
    private int whiteUser;

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    private static int countChessNumber = 0;

    //棋盘用二维数组表示
    //初始化全0,0表示当前位置未落子
    //1表示user1 的落子位置
    //2表示user2 的落子位置
    private int[][] board = new int[MAX_ROW][MAX_COL];

    //创建ObjectMapper 来转换JSON
    private ObjectMapper objectMapper = new ObjectMapper();

    //引入OnlineUserManager
    //application
    private OnlineUserManager onlineUserManager;

    //引入RoomManager 用于房间销毁
    private RoomManager roomManager;

    private UserMapper userMapper;

    //处理落子操作的方法::::核心步骤::::
    public void putChess(String reqJson) throws IOException {
        //1.记录当前落子的位置
        GameRequest request = objectMapper.readValue(reqJson, GameRequest.class);
        GameResponse response = new GameResponse();
        //根据落子的玩家来决定写入数组的是1or2
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        //再次判定重复落子情况,万无一失
        if (board[row][col] != 0) {
            System.out.println("当前位置 (" + row + col + ") 已经落子了");
            return;
        }
        board[row][col] = chess;

        //2.打印出当前的棋盘信息,方便胜负判定
        printBoard();

        //3.进行胜负的判定
        int winner = checkWinner(row, col, chess);

        //4.给房间中的所有客户断都返回响应
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);

        //想要给用户发送websoccket数据, 需要先获取websocketSession
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        //万一当前能查到的会话为空,即玩家已下线,处理
        if (session1 == null) {
            //玩家1下线,玩家2直解胜利
            response.setWinner(user2.getUserId());
            System.out.println("玩家 :" + user1.getUserId() + "掉线");
        }
        if (session2 == null) {
            //同理
            response.setWinner(user1.getUserId());
            System.out.println("玩家 :" + user2.getUserId() + "掉线");
        }

        //把响应构造成JSON字符串,通过 session 进行传输
        String respJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(respJson));
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(respJson));
        }

        //5.如果当前胜负已分, 此时房间就应该销毁
        if (response.getWinner() != 0 && response.getWinner() != -1) {
            System.out.println("对局结束,玩家 : " + response.getWinner() + "获胜");
            //更新双方信息
            int winUserId = response.getWinner();
            int loseUserid = response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserid);
            //销毁房间
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
        if (response.getWinner() == -1) {
            System.out.println("平局 旗鼓相当的对手");
            //更新双方信息
            int hah1UserId = user1.getUserId();
            int hah2UserId = user2.getUserId();
            userMapper.userHah(hah1UserId);
            userMapper.userHah(hah2UserId);
            //销毁房间
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

    //谁获胜返回谁的userId,胜负不分则返回0
    private int checkWinner(int row, int col, int chess) {
        //1.检查所有行
        for (int c = col - 4; c <= col; c++) {
            //针对其中一种情况判定,玩家的五个子是不是连着
            try {
                if (board[row][c] == chess
                        && board[row][c + 1] == chess
                        && board[row][c + 2] == chess
                        && board[row][c + 3] == chess
                        && board[row][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                //如果出现数组下标越界异常,直接忽略
                continue;
            }
        }

        //2.检查所有列
        for (int r = row - 4; r <= row; r++) {
            try {
                if (board[r][col] == chess
                        && board[r + 1][col] == chess
                        && board[r + 2][col] == chess
                        && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //3.检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c + 1] == chess
                        && board[r + 2][c + 2] == chess
                        && board[r + 3][c + 3] == chess
                        && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //4.检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--) {
            try {
                if (board[r][c] == chess
                        && board[r + 1][c - 1] == chess
                        && board[r + 2][c - 2] == chess
                        && board[r + 3][c - 3] == chess
                        && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        //胜负未分
        boolean isFull = true;
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < MAX_COL; c++) {
                if (board[r][c] == 0) {
                    isFull = false; // 如果发现有空位，棋盘未满
                    break;
                }
            }
        }

        if (isFull) {
            return -1; // 棋盘已满但未分胜负
        }

        return 0; // 胜负未分，棋盘未满
    }

    //打印棋盘
    private void printBoard() {
        System.out.println("[打印棋盘信息] " + roomId +" 落子次数: " + ++countChessNumber);
//        System.out.println("=====================================================================");
//        for (int r = 0; r < MAX_ROW; r++) {
//            for (int c = 0; c < MAX_COL; c++) {
//                System.out.print(board[r][c] + " ");
//            }
//            System.out.println();
//        }
//        System.out.println("=====================================================================");
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }

    public int getWhiteUser() {
        return whiteUser;
    }

    public void setWhiteUser(int whiteUser) {
        this.whiteUser = whiteUser;
    }

    public Room() {
        //使用UUID作为房间唯一id
        roomId = UUID.randomUUID().toString();

        //通过入口类中记录的 context 来手动获取起前面 的 RoomManager 和 OnlineUserManager
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }


    public static void main(String[] args) {
        Room room = new Room();
        System.out.println(room.roomId);
    }
}
